package cn.anc.aonicardv.media;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer;
import android.net.Network;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;

import java.io.IOException;


/**
 * Created by yangdai on 2017/11/11.
 */

public class MediaPlayerVideoView extends FrameLayout implements MediaOperation, PlayerLifeCycle, View.OnClickListener, TextureView.SurfaceTextureListener {

    private static final String TAG = MediaPlayerVideoView.class.getSimpleName();
    private static final int sDefaultTimeout = 3000;
    private static final int STATE_ERROR = -1;
    private static final int STATE_IDLE = 0;
    private static final int STATE_PREPARING = 1;
    private static final int STATE_PREPARED = 2;
    private static final int STATE_PLAYING = 3;
    private static final int STATE_PAUSED = 4;
    private static final int STATE_PLAYBACK_COMPLETED = 5;
    private static final int STATE_RESUME = 7;
    private String mUrl;
    private Uri mUri;
    private long mDuration;
    private long mLastPosition;
    private int mCurrentState = STATE_IDLE;
    private int mTargetState = STATE_IDLE;
    protected MediaPlayer mMediaPlayer;
    private MediaController mMediaController;
    private View mMediaBufferingIndicator;
    private MediaPlayer.OnCompletionListener mOnCompletionListener;
    private MediaPlayer.OnPreparedListener mOnPreparedListener;
    private MediaPlayer.OnErrorListener mOnErrorListener;
    private MediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener;
    private MediaPlayer.OnInfoListener mOnInfoListener;
    private MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener;
    private int mCurrentBufferPercentage;
    private boolean isDestroy = true;
    private boolean isAutoResume = true;
    private Context mContext;
    private TextureView mTextureView;
    private View mBlackBackground;
    private boolean mIsHideNavigation;
    private boolean mIsSeekAfterBuffering;
    private boolean mIsReBufferring;
    private boolean mIsLooping;

    MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
        public void onPrepared(MediaPlayer mp) {
            Log.d(TAG, "onPrepared: ");
            mCurrentState = STATE_PREPARED;
            if (mTargetState != STATE_PAUSED)
                mTargetState = STATE_PLAYING;
            if (mOnPreparedListener != null) {
                mOnPreparedListener.onPrepared(mMediaPlayer);
            }
            start();
        }
    };

    private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
        public void onCompletion(MediaPlayer mp) {
            mCurrentState = STATE_PLAYBACK_COMPLETED;
            mTargetState = STATE_PLAYBACK_COMPLETED;
            isAutoResume = false;
            updateControllerState(STATE_IDLE);
            Runtime.getRuntime().gc();
            if (mMediaController != null && getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
                exitFullScreen();
            if (mOnCompletionListener != null) {
                mOnCompletionListener.onCompletion(mMediaPlayer);
            }
        }
    };

    private MediaPlayer.OnErrorListener mErrorListener = new MediaPlayer.OnErrorListener() {
        public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
            Log.d(TAG, "onError: " + framework_err + "," + impl_err);
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            if (mOnErrorListener != null) {
                if (mOnErrorListener.onError(mMediaPlayer, framework_err,
                        impl_err)) {
                    return true;
                }
            }
            return true;
        }
    };

    private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
        public void onBufferingUpdate(MediaPlayer mp, int percent) {
            if (percent == mCurrentBufferPercentage) {
                mIsSeekAfterBuffering = true;
            } else {
                mIsSeekAfterBuffering = false;
                mIsReBufferring = true;
            }
            if (mIsSeekAfterBuffering && mIsReBufferring && mMediaPlayer.getCurrentPosition() == mLastPosition) {
                if (mCurrentState != STATE_PAUSED && mTargetState != STATE_PAUSED) {
                    mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() + 1);
                    mIsReBufferring = false;
                } else {
                    if (mMediaBufferingIndicator != null)
                        mMediaBufferingIndicator.setVisibility(GONE);
                    if (mMediaPlayer.isPlaying())
                        onPause();
                }
            }
            mCurrentBufferPercentage = percent;
            mLastPosition = mMediaPlayer.getCurrentPosition();
            if (mOnBufferingUpdateListener != null) {
                mOnBufferingUpdateListener.onBufferingUpdate(mp, percent);
            }
        }
    };

    private MediaPlayer.OnInfoListener mInfoListener = new MediaPlayer.OnInfoListener() {
        @Override
        public boolean onInfo(MediaPlayer mp, int what, int extra) {
            Log.d(TAG, "onInfo: " + what + "," + extra);
            if (mMediaPlayer != null) {
                if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
                    if (mMediaBufferingIndicator != null)
                        mMediaBufferingIndicator.setVisibility(VISIBLE);
                    if (mMediaController != null) {
                        mMediaController.show(0);
                    }
                } else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END || what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
                    if (mMediaBufferingIndicator != null)
                        mMediaBufferingIndicator.setVisibility(GONE);
                    if (mMediaController != null)
                        mMediaController.show(sDefaultTimeout);
                }
            }
            if (mOnInfoListener != null) {
                mOnInfoListener.onInfo(mp, what, extra);
            }
            return true;
        }
    };

    private MediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new MediaPlayer.OnSeekCompleteListener() {
        @Override
        public void onSeekComplete(MediaPlayer mp) {
            Log.d(TAG, "onSeekComplete: ");
            if (mOnSeekCompleteListener != null) {
                mOnSeekCompleteListener.onSeekComplete(mp);
            }
        }
    };

    public MediaPlayerVideoView(Context context) {
        this(context, null);
    }

    public MediaPlayerVideoView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MediaPlayerVideoView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initVideoView(context);
    }

    private void initVideoView(Context ctx) {
        mContext = ctx;
        mTextureView = new TextureView(getContext());
        mBlackBackground = new View(getContext());
        mBlackBackground.setBackgroundColor(Color.BLACK);
        mTextureView.setSurfaceTextureListener(this);
        mTextureView.setOnClickListener(this);
        mTextureView.setFocusable(true);
        setFocusableInTouchMode(true);
        requestFocus();
        mCurrentState = STATE_IDLE;
        mTargetState = STATE_IDLE;
    }

    public void setDataSource(String url) {
        this.mUrl = url;
        this.mUri = null;
    }

    public void setDataSource(Uri uri) {
        this.mUri = uri;
        this.mUrl = null;
    }

    public void reset() {
        if (mMediaPlayer != null)
            mMediaPlayer.reset();
    }

    public void stopPlayback() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mCurrentState = STATE_IDLE;
            mTargetState = STATE_IDLE;
        }
        updateControllerState(STATE_IDLE);
    }

    private void openVideo() {
        if (mUrl == null && mUri == null) {
            return;
        }
        try {
            mDuration = -1;
            mCurrentBufferPercentage = 0;
            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setOnPreparedListener(mPreparedListener);
            mMediaPlayer.setOnCompletionListener(mCompletionListener);
            mMediaPlayer.setOnErrorListener(mErrorListener);
            mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
            mMediaPlayer.setOnInfoListener(mInfoListener);
            mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
            if (mUrl != null) {
                mMediaPlayer.setDataSource(mUrl);
            }
            if (mUri != null)
                mMediaPlayer.setDataSource(mContext, mUri);
            mMediaPlayer.setLooping(mIsLooping);
            mMediaPlayer.setSurface(mSurface);
            mMediaPlayer.prepareAsync();
            mCurrentState = STATE_PREPARING;
        } catch (IOException | IllegalArgumentException ex) {
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            mErrorListener.onError(mMediaPlayer,
                    MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
        }
    }

    public void setMediaController(MediaController mediaController) {
        try {
            if (mMediaController != null) {
                ViewGroup viewGroup = (ViewGroup) mMediaController;
                viewGroup.removeView(mMediaBufferingIndicator);
                mediaController.setMediaBufferingIndicator(mMediaBufferingIndicator, mMediaBufferingIndicator.getLayoutParams());
            }
            mMediaController = mediaController;
            removeAllViews();
            addPlayerView(this);
            attachMediaController();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void addPlayerView(ViewGroup container) {
        try {

            container.addView(mBlackBackground);
            container.addView(mTextureView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            if (mMediaController != null)
                container.addView((ViewGroup) mMediaController, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setVideoSize(int width, int height) {
        ViewGroup.LayoutParams layoutParams = getLayoutParams();
        if (width != 0)
            layoutParams.width = width;
        if (height != 0)
            layoutParams.height = height;
        setLayoutParams(layoutParams);
    }

    public void setMediaBufferingIndicator(View mediaBufferingIndicator, ViewGroup.LayoutParams layoutParams) {
        if (mediaBufferingIndicator != null) {
            mMediaBufferingIndicator = mediaBufferingIndicator;
            mMediaBufferingIndicator.setVisibility(GONE);
            if (mMediaController != null && layoutParams != null)
                mMediaController.setMediaBufferingIndicator(mMediaBufferingIndicator, layoutParams);
        }
    }

    private void attachMediaController() {
        if (mMediaController != null) {
            mMediaController.setMediaPlayer(this);
        }
    }

    public MediaController getMediaController() {
        return mMediaController;
    }

    public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
        mOnPreparedListener = l;
    }

    public void setOnCompletionListener(MediaPlayer.OnCompletionListener l) {
        mOnCompletionListener = l;
    }

    public void setOnErrorListener(MediaPlayer.OnErrorListener l) {
        mOnErrorListener = l;
    }

    public void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener l) {
        mOnBufferingUpdateListener = l;
    }

    public void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener l) {
        mOnSeekCompleteListener = l;
    }

    public void setOnInfoListener(MediaPlayer.OnInfoListener l) {
        mOnInfoListener = l;
    }

    public void releasePlayer() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
            mCurrentState = STATE_IDLE;
            mTargetState = STATE_IDLE;
        }
        updateControllerState(STATE_IDLE);
    }

    @Override
    public boolean onTrackballEvent(MotionEvent ev) {
        if (isInPlaybackState() && mMediaController != null) {
            toggleMediaControlsVisiblity();
        }
        return false;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        boolean isKeyCodeSupported =
                keyCode != KeyEvent.KEYCODE_BACK
                        &&
                        keyCode != KeyEvent.KEYCODE_VOLUME_UP
                        && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN
                        && keyCode != KeyEvent.KEYCODE_MENU
                        && keyCode != KeyEvent.KEYCODE_CALL
                        && keyCode != KeyEvent.KEYCODE_ENDCALL;
        if (isInPlaybackState() && isKeyCodeSupported
                && mMediaController != null) {
            if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
                    || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
                    || keyCode == KeyEvent.KEYCODE_SPACE) {

                if (mMediaPlayer.isPlaying()) {
                    pause();
                    mMediaController.show(sDefaultTimeout);
                } else {
                    start();
                    mMediaController.hide();
                }
                return true;
            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
                    && mMediaPlayer.isPlaying()) {
                pause();
                mMediaController.show(sDefaultTimeout);
            } else {
                toggleMediaControlsVisiblity();
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    private void toggleMediaControlsVisiblity() {
        if (mMediaController.isShowing()) {
            mMediaController.hide();
        } else {
            mMediaController.show(sDefaultTimeout);
        }
    }

    @Override
    public void start() {
        if (mMediaPlayer == null) {
            openVideo();
            updateControllerState(MediaController.STATE_PREPARING);
            mCurrentState = STATE_PREPARING;
        } else {
            if (mTargetState != STATE_PAUSED)
                mTargetState = STATE_PLAYING;
            if (isInPlaybackState()) {
                mMediaPlayer.start();
                mCurrentState = STATE_PLAYING;
            }
            updateControllerState(MediaController.STATE_PLAYING);
        }
        isAutoResume = true;
    }

    private void updateControllerState(int state) {
        if (mMediaController != null)
            mMediaController.updateControllerState(state);
    }

    @Override
    public void pause() {
        if (isInPlaybackState()) {
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
                mCurrentState = STATE_PAUSED;
            }
        }
        mTargetState = STATE_PAUSED;
        isAutoResume = false;
        updateControllerState(MediaController.STATE_PAUSED);
    }

    public void resume() {

        if (isInPlaybackState() && mCurrentState == STATE_PAUSED
                ) {
            mCurrentState = STATE_RESUME;
            mMediaPlayer.start();
        }
        updateControllerState(MediaController.STATE_RESUME);
        mTargetState = STATE_RESUME;
        isAutoResume = true;
        isDestroy = true;
    }

    @Override
    public int getDuration() {
        if (isInPlaybackState()) {
            if (mDuration > 0) {
                return (int) mDuration;
            }
            mDuration = mMediaPlayer.getDuration();
            return (int) mDuration;
        }
        mDuration = -1;
        return (int) mDuration;
    }

    @Override
    public int getCurrentPosition() {
        if (isInPlaybackState()&&mMediaPlayer!=null) {
            long position = mMediaPlayer.getCurrentPosition();
            return (int) position;
        }
        return 0;
    }

    @Override
    public void seekTo(long msec) {
        if (isInPlaybackState()) {
            mMediaPlayer.seekTo((int) msec);
        }
    }

    @Override
    public boolean isPlaying() {
        return isInPlaybackState() && mMediaPlayer.isPlaying();
    }

    @Override
    public int getBufferPercentage() {
        if (mMediaPlayer != null) {
            return mCurrentBufferPercentage;
        }
        return 0;
    }

    @Override
    public void setAutoReconnect(boolean autoConnect) {
    }

    @Override
    public void setNetwork(Network network) {
    }

    public void fullScreen() {
        isDestroy = false;
        mMediaController.setExitFullScreenBtnVisibility(true);
        mMediaController.setFullScreenBtnVisibility(false);
        Activity activity = (Activity) getContext();
        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        hideNavigationBar(true);
        ViewGroup vp = (ViewGroup) activity.getWindow().getDecorView().findViewById(Window.ID_ANDROID_CONTENT);
        removeAllViews();
        addPlayerView(vp);
    }

    public void exitFullScreen() {
        isDestroy = false;
        mMediaController.setExitFullScreenBtnVisibility(false);
        mMediaController.setFullScreenBtnVisibility(true);
        Activity activity = (Activity) getContext();
        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        hideNavigationBar(false);
        ViewGroup vp = (ViewGroup) activity.getWindow().getDecorView().findViewById(Window.ID_ANDROID_CONTENT);
        vp.removeView(mBlackBackground);
        vp.removeView(mTextureView);
        vp.removeView((View) mMediaController);
        addPlayerView(this);
    }

    public void hideNavigationBar(boolean isHide) {
        mIsHideNavigation = isHide;
        if (mIsHideNavigation) {
            setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
        } else {
            setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
        }
    }

    protected boolean isInPlaybackState() {
        return (mMediaPlayer != null && mCurrentState != STATE_ERROR
                && mCurrentState != STATE_PREPARING);
    }

    @Override
    public void setVolume(float volume) {
        mMediaPlayer.setVolume(volume, volume);
    }

    public void setLooping(boolean isLoop) {
        mIsLooping = isLoop;
    }

    @Override
    public void onResume() {
        if (isInPlaybackState() && isAutoResume) {
            resume();
        }
        if (mIsHideNavigation) {
            hideNavigationBar(true);
        }
    }

    @Override
    public void onPause() {
        if (mCurrentState != STATE_PLAYBACK_COMPLETED && mCurrentState != STATE_IDLE) {
            if (isInPlaybackState() && isAutoResume) {
                mMediaPlayer.pause();
                mCurrentState = STATE_PAUSED;
            }
            mTargetState = STATE_PAUSED;
            isDestroy = false;
            updateControllerState(MediaController.STATE_PAUSED);
        }
    }

    @Override
    public void onClick(View v) {
        if (isInPlaybackState() && mMediaController != null && mCurrentState != STATE_PLAYBACK_COMPLETED
                && (mMediaBufferingIndicator == null || mMediaBufferingIndicator.getVisibility() != VISIBLE)
                ) {
            toggleMediaControlsVisiblity();
        }
    }

    Surface mSurface;

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        mSurface = new Surface(surface);
        if (mMediaPlayer != null)
            mMediaPlayer.setSurface(mSurface);
        if (mMediaController != null) {
            if (mMediaBufferingIndicator != null && mMediaBufferingIndicator.getVisibility() == VISIBLE
                    || mCurrentState == STATE_PLAYBACK_COMPLETED ||
                    mCurrentState == STATE_IDLE
                    ) {
                mMediaController.show(0);
            } else
                mMediaController.show(sDefaultTimeout);
        }
        isDestroy = true;
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        if (isDestroy) {
            releasePlayer();
        }
        if (mMediaPlayer != null) {
            mMediaPlayer.setDisplay(null);
        }
        if (mSurface != null)
            mSurface.release();
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }
}
